---
id: transformation
title: Transforming objects in the scene
sidebar_label: Transformation
slug: /guides/transformation
---

import useBaseUrl from '@docusaurus/useBaseUrl'

Transforming refers to changing the position, rotation or scale of an object in the scene.

<div class="image-container">
  <svg xmlns="http://www.w3.org/2000/svg" width="283" height="535">
    <image href={useBaseUrl("img/demo-transformation.gif")} x="18" y="33" width="247" height="469" />
    <image href={useBaseUrl("img/frame.png")} width="283" height="535" />
  </svg>
</div>

## Translate / Position

By default models are rendered at the origin `[0, 0, 0]`. You can change the position of a model by providing a `translate` prop:

```tsx
import { Model } from "react-native-filament"

const x = 0
const y = -1
const z = 0

<Model translate={[x, y, z]} />
```

Units in filament are physically based, so 1 unit is 1 meter.

## Rotation

You can rotate a model by providing a `rotation` prop:

```tsx
import { Model } from "react-native-filament"

const rotationInDegree = 45;
const angleInRadians = rotationInDegree * (Math.PI / 180);
const rotateOnAxis = [0, angleInRadians, 0]; // Rotate on the y-axis

<Model rotate={rotateOnAxis} />
```

The `rotation` props expects a 3D vector (called `Float3` in RNF), where each value represents the rotation in radians around the x, y and z axis respectively.

## Scale

You can scale a model by providing a `scale` prop for the x, y and z axis:

```tsx
import { Model } from "react-native-filament"

const scale = 2;

<Model scale={[scale, scale, scale]} />
```

## Matrix multiplication

By default the transformation props are being multiplied to the current transform of the model. They are being multiplied in the order `scale` -> `rotation` -> `position` (SRT).
This means that if you first apply a scale of `[2,2,2]` and then later apply a scale of `[3,3,3]` the final scale will be `[6,6,6]`. To avoid this behaviour you
can specify the `multiplyWithCurrentTransform` prop and set it to false to disable this behaviour:

```tsx
import { Model } from "react-native-filament"

function GrowingModel() {
  const [scale, setScale] = useState(1);
  const growModel = () => setScale(scale + 1);

  return (
    <Model
      scale={[scale, scale, scale]}
      // Disables multiplication with current, and grows the model by 1 unit each time growModel is called
      multiplyWithCurrentTransform={false}
    />
  )
}
```

:::warning
When **disabling** the multiplication with the current transform, you'll reset all previous transformations (including rotation and position) and only apply the new transformations.
:::

:::warning
When matrix multiplication is **enabled (default)** all transform operations will be applied on a fast refresh. Keep this in mind during development if something starts to look off.
:::

## Animate the transform props

You may want to change the transformation props very frequently (e.g. every frame). To avoid performance issues, you should **not** update the props using `useState` directly, but use shared values.

You may know shared values from `reanimated`. We are using the shared values from `react-native-worklets-core`, but they work very similary.

You can create a new shared value using `useSharedValue`:


```tsx
import { useSharedValue } from "react-native-worklets-core";

function MyScene() {
  const rotation = useSharedValue(0);

  // ...
}
```

You can pass a shared value to any of the transformation props:

```tsx
function MyScene() {
  const rotation = useSharedValue<Float3>([0, 0, 0]);

  return <Model rotate={rotation} />
}
```

Now, lets update the rotation value every frame:

```tsx
import { useCallback } from 'react'
import { useSharedValue } from "react-native-worklets-core"
import { RenderCallback, FilamentView, Model, Float3 } from "react-native-filament"

function MyScene() {
  const rotation = useSharedValue<Float3>([0, 0, 0]);

  const renderCallback: RenderCallback = useCallback(() => {
    "worklet"

    // Add a rotation of 1 degree every frame
    const newY = rotation.value[1] + 0.01,

    // We need to create a new array for the internal listeners to trigger
    rotation.value = [0, newY, 0]
  }, [rotation])

  return (
    <FilamentView renderCallback={renderCallback}>
      <Model rotate={rotation} />
    </FilamentView>
  )
}
```

## Transform to unit cube

There is a helper prop that you can use called `transformToUnitCube` which will make the asset fit into a 1x1x1 (unit) cube.

## Apply imperatively using `TransformManager`

Sometimes you have use cases where you want to update a model's transformation imperatively.
For this we can use the [`TransformManager`](../api/interfaces/TransformManager) directly.

For this, you first need to render the model using the `useModel` and the accompanying `ModelRenderer` component:

```tsx
import { useModel, ModelRenderer } from "react-native-filament"

function MyScene() {
  const model = useModel(MyModel)

  return <ModelRenderer model={model} />
}
```

`ModelRenderer` accepts all props that `Model` does. 

The `TransformManager` only works on entities, so we need to select one first. A model is made out of many entities. When transforming our model we usually want to transform all entities of the model (isValidElement. the whole model).
For that we can use the `rootEntity`:

```tsx
import { useModel } from "react-native-filament"

const model = useModel(MyModel)
const rootEntity = model.state === "loaded" ? model.rootEntity : undefined
```

Now we can use the `TransformManager` to apply transformations. For example for rotating a model continuously, we can just apply a multipying rotation every frame:

```tsx
import { useCallback } from 'react'
import { TransformManager, useModel, RenderCallback } from "react-native-filament"

function MyScene() {
  const model = useModel(MyModel)
  const rootEntity = model.state === "loaded" ? model.rootEntity : undefined

  // We get the transformManager for the filament context.
  // For this to work <MyScene /> needs to be wrapped with a <FilamentScene>
  const { transformManager } = useFilamentContext()

  const renderCallback: RenderCallback = useCallback(() => {
    "worklet"

    // We have to check if the model is ready yet:
    if (rootEntity == null) return;

    // Add a rotation of 1 degree every frame on the y-axis and 
    // multiply it with the current transform by setting `true` as last argument
    transformManager.setEntityRotation(rootEntity, 0.01, [0, 1, 0], true)
  }, [rootEntity, transformManager])
}
```

The `transformManager` has lots of APIs, you can [check them out in the API docs](../api/interfaces/TransformManager).

### Setting all transform data yourself

Using the `transformManager` its also possible to manually set a 4x4 matrix yourself, using a 16 element array:

```tsx
transformManager.setTransform(entity, [
  1, 0, 0, 0,
  0, 1, 0, 0,
  0, 0, 1, 0,
  0, 0, 0, 1
])
```

Matrices in filament are column-major.